package com.ia.aistream.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.google.common.collect.Maps;
import com.ia.aistream.common.utils.StringUtils;
import com.ia.aistream.common.utils.spring.SpringUtils;
import com.ia.aistream.manager.framework.config.properties.ShiroConf;
import com.ia.aistream.manager.framework.filter.impl.BearerHeaderTokenFilter;
import com.ia.aistream.manager.framework.shiro.realm.OpenUserRealm;
import com.ia.aistream.manager.framework.shiro.realm.UserRealm;
import com.ia.aistream.manager.framework.shiro.session.OnlineSessionDAO;
import com.ia.aistream.manager.framework.shiro.session.OnlineSessionFactory;
import com.ia.aistream.manager.framework.shiro.web.filter.LogoutFilter;
import com.ia.aistream.manager.framework.shiro.web.filter.captcha.CaptchaValidateFilter;
import com.ia.aistream.manager.framework.shiro.web.filter.kickout.KickoutSessionFilter;
import com.ia.aistream.manager.framework.shiro.web.filter.online.OnlineSessionFilter;
import com.ia.aistream.manager.framework.shiro.web.filter.sync.SyncOnlineSessionFilter;
import com.ia.aistream.manager.framework.shiro.web.session.OnlineWebSessionManager;
import com.ia.aistream.manager.framework.shiro.web.session.SpringSessionValidationScheduler;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;


/**
 * 权限配置加载
 * 
 * @author ia
 */
@Configuration
public class ShiroConfig
{

    //拦截地址
    @Autowired(required = false)
    private ShiroConf shiroConf;

    /**
     * 缓存管理器 使用Ehcache实现
     * 这是配置shiro的缓存管理器org.apache.shiro.cache.ehcach.EhCacheManager，
     * 方法的参数是把spring容器中的cacheManager对象注入到EhCacheManager中，
     * 这样就实现了shiro和缓存注解使用同一种缓存方式
     */
    @Bean
    public EhCacheManager getEhCacheManager()
    {
        net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("aistream");
        EhCacheManager em = new EhCacheManager();
        if (StringUtils.isNull(cacheManager))
        {
            em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));
            return em;
        }
        else
        {
            em.setCacheManager(cacheManager);
            return em;
        }
    }

    /**
     * 返回配置文件流 避免ehcache配置文件一直被占用，无法完全销毁项目重新部署
     */
    protected InputStream getCacheManagerConfigFileInputStream()
    {
        String configFile = "classpath:ehcache/ehcache-shiro.xml";
        InputStream inputStream = null;
        try
        {
            inputStream = ResourceUtils.getInputStreamForPath(configFile);
            byte[] b = IOUtils.toByteArray(inputStream);
            InputStream in = new ByteArrayInputStream(b);
            return in;
        }
        catch (IOException e)
        {
            throw new ConfigurationException(
                    "Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e);
        }
        finally
        {
            IOUtils.closeQuietly(inputStream);
        }
    }

    /* ************************************************************** 拦截器开始 ************************************************************** */
    /**
     * BearerToken拦截器
     *
     * @return
     */
    @Bean()
    public BearerHeaderTokenFilter bearerTokenFilter() {
        return new BearerHeaderTokenFilter();
    }

    @Bean
    public FilterRegistrationBean<BearerHeaderTokenFilter> bearerTokenFilterRegistration(BearerHeaderTokenFilter filter) {
        FilterRegistrationBean<BearerHeaderTokenFilter> registration = new FilterRegistrationBean<>(filter);
        // 是否启用，如果值为false，则不启用该，SpringBoot自动帮我们注册了我们的Filter需要去掉springboot启用
        registration.setEnabled(false);
        return registration;
    }

    /* ************************************************************** 拦截器结束 ************************************************************** */

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    /**
     * 自定义Realm
     */
    @Bean
    public OpenUserRealm userRealm()
    {
        OpenUserRealm userRealm = new OpenUserRealm();
        return userRealm;
    }



    /**
     * 安全管理器
     */
    @Bean
    public SecurityManager securityManager()
    {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(userRealm());
        return securityManager;
    }


    /**
     * Shiro过滤器配置
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager)
    {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // Shiro的核心安全接口,这个属性是必须的
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 身份认证失败，则跳转到登录页面的配置
        shiroFilterFactoryBean.setLoginUrl(shiroConf.getUser().getLoginUrl());
        // 权限认证失败，则跳转到指定页面
        shiroFilterFactoryBean.setUnauthorizedUrl(shiroConf.getUser().getUnauthorizedUrl());
        // 系统权限列表
        // filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());*/
        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
        filters.put("bearer", bearerTokenFilter());
        shiroFilterFactoryBean.setFilters(filters);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroConf.getFilterChainDefinitionMap());

        return shiroFilterFactoryBean;
    }




    /**
     * 开启Shiro注解通知器
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
           SecurityManager securityManager)
    {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}
